// Access to DSymLoad.ini

// ----------------------------------------------------------------------------

#include "stdafx.h"

#include "DSymLoadError.h"
#include "DSymLoadSettings.h"

// ----------------------------------------------------------------------------

namespace DSymLoad
{

// ----------------------------------------------------------------------------

const std::array<CSettingsIniEntry, SettingsEntryBool::CountOf> CSettings::g_IniEntryBools =
{
    CSettingsIniEntry("Common", "OverrideIfExist"),
    CSettingsIniEntry("Common", "ProcessNameCollision"),
    CSettingsIniEntry("Symbols", "NoCpp"),
    CSettingsIniEntry("Symbols", "UndName"),
};

// ----------------------------------------------------------------------------

const std::array<CSettingsIniEntry, SettingsEntryString::CountOf> CSettings::g_IniEntryStrings =
{
    CSettingsIniEntry("Symbols", "SymPath"),
    CSettingsIniEntry("Symbols", "LibPath"),
};

// ----------------------------------------------------------------------------

CSettings::CSettings(__in HMODULE hModule)
{
    _ASSERT(hModule);

    const auto nChars = ::GetModuleFileNameA(hModule, m_csFileName.GetBuffer(MAX_PATH), MAX_PATH);
    if (!nChars)
        throw MakeFunctionCallError("GetModuleFileName");
    m_csFileName.ReleaseBuffer(nChars);

    const auto nDotPosition = m_csFileName.ReverseFind('.');
    if (-1 == nDotPosition)
        throw CError(CStringA("Invalid DLL file name: ") + CStringA(m_csFileName));

    m_csFileName =  m_csFileName.Left(nDotPosition + 1) + "ini";

    Reset();
}

// ----------------------------------------------------------------------------

void CSettings::Reset()
{
    m_Bools[SettingsEntryBool::OverrideIfExist]         = true;
    m_Bools[SettingsEntryBool::ProcessNameCollision]    = true;
    m_Bools[SettingsEntryBool::NoCpp]                   = false;
    m_Bools[SettingsEntryBool::UndName]                 = true;
}

// ----------------------------------------------------------------------------

void CSettings::Load()
{
    for (int i = 0; i < SettingsEntryBool::CountOf; ++i)
        Read(g_IniEntryBools[i], m_Bools[i]);

    for (int i = 0; i < SettingsEntryString::CountOf; ++i)
        Read(g_IniEntryStrings[i], m_Strings[i]);
}

// ----------------------------------------------------------------------------

void CSettings::Save() const
{
    for (int i = 0; i < SettingsEntryBool::CountOf; ++i)
        Write(g_IniEntryBools[i], m_Bools[i]);

    for (int i = 0; i < SettingsEntryString::CountOf; ++i)
        Write(g_IniEntryStrings[i], m_Strings[i]);
}

// ----------------------------------------------------------------------------

bool CSettings::IsOverrideIfExist() const
{
    return m_Bools[SettingsEntryBool::OverrideIfExist];
}

// ----------------------------------------------------------------------------

void CSettings::SetOverrideIfExist(bool bOverrideIfExist)
{
    m_Bools[SettingsEntryBool::OverrideIfExist] = bOverrideIfExist;
}

// ----------------------------------------------------------------------------

bool CSettings::IsProcessNameCollision() const
{
    return m_Bools[SettingsEntryBool::ProcessNameCollision];
}

// ----------------------------------------------------------------------------

void CSettings::SetProcessNameCollision(bool bProcessNameCollision)
{
    m_Bools[SettingsEntryBool::ProcessNameCollision] = bProcessNameCollision;
}

// ----------------------------------------------------------------------------

bool CSettings::IsNoCpp() const
{
    return m_Bools[SettingsEntryBool::NoCpp];
}

// ----------------------------------------------------------------------------

void CSettings::SetNoCpp(bool bNoCpp)
{
    m_Bools[SettingsEntryBool::NoCpp] = bNoCpp;
}

// ----------------------------------------------------------------------------

bool CSettings::IsUndName() const
{
    return m_Bools[SettingsEntryBool::UndName];
}

// ----------------------------------------------------------------------------

void CSettings::SetUndName(bool bUndName)
{
    m_Bools[SettingsEntryBool::UndName] = bUndName;
}

// ----------------------------------------------------------------------------

const CStringA &CSettings::GetSymPath() const
{
    return m_Strings[SettingsEntryString::SymPath];
}

// ----------------------------------------------------------------------------

void CSettings::SetSymPath(const CStringA &csSymPath)
{
    m_Strings[SettingsEntryString::SymPath] = csSymPath;
}

// ----------------------------------------------------------------------------

const CStringA &CSettings::GetLibPath() const
{
    return m_Strings[SettingsEntryString::LibPath];
}

// ----------------------------------------------------------------------------

void CSettings::SetLibPath(const CStringA &csLibPath)
{
    m_Strings[SettingsEntryString::LibPath] = csLibPath;
}

// ----------------------------------------------------------------------------

CStringA CSettings::FormatBool(bool bValue)
{
    return CStringA(bValue ? "true" : "false");
}

// ----------------------------------------------------------------------------

void CSettings::Read(
    __in const CSettingsIniEntry &IniEntry,
    __out bool &bValue
)
{
    CStringA csBoolValue;
    Read(IniEntry, csBoolValue);
    if (!csBoolValue.CompareNoCase("true"))
        bValue = true;
    else if (!csBoolValue.CompareNoCase("false"))
        bValue = false;
}

// ----------------------------------------------------------------------------

void CSettings::Read(
    __in const CSettingsIniEntry &IniEntry,
    __out CStringA &csValue
)
{
    csValue.ReleaseBuffer(
        ::GetPrivateProfileStringA(
            IniEntry.m_szSectionName,
            IniEntry.m_szKeyName,
            nullptr,
            csValue.GetBuffer(MAX_PATH),
            MAX_PATH,
            m_csFileName)
    );
}

// ----------------------------------------------------------------------------

void CSettings::Write(
    __in const CSettingsIniEntry &IniEntry,
    __in bool bValue
) const
{
    Write(IniEntry, FormatBool(bValue));
}

// ----------------------------------------------------------------------------

void CSettings::Write(
    __in const CSettingsIniEntry &IniEntry,
    __in const CStringA &csValue
) const
{
    const auto Writed = 
        ::WritePrivateProfileStringA(
            IniEntry.m_szSectionName,
            IniEntry.m_szKeyName,
            csValue, m_csFileName);
    if (!Writed)
    {
        const auto nErrorCode = ::GetLastError();
        throw 
            MakeFunctionCallError(
                "WritePrivateProfileString",
                CStringA("(") + 
                    CStringA(IniEntry.m_szSectionName) + 
                    CStringA(", ") + 
                    CStringA(IniEntry.m_szKeyName) + 
                    CStringA(", ...)"),
                nErrorCode);
    }
}

// ----------------------------------------------------------------------------

}   // namespace DSymLoad

// ----------------------------------------------------------------------------

